package com.ch3cooh.rpc.controller;

import com.alibaba.fastjson.JSON;
import com.ch3cooh.proxy.pojo.ClassInfo;
import com.ch3cooh.proxy.util.OkHttpClientUtil;
import com.ch3cooh.registry.util.StringUtils;
import com.ch3cooh.rpc.component.LocalServerManager;
import com.ch3cooh.rpc.util.ScannerUtils;
import com.ch3cooh.rpc.util.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@RestController
@RequestMapping("/rpc")
public class RpcService{

    private static final String functionUri = "/rpc/invoke";

    private  static Map<String,List<Class>> rpcMap = null;

    {
        rpcMap = ScannerUtils.mapInterfaceImpl("");
    }

    /**
     *
     * @param classInfo
     * @param methodReturnType 方法返回的对象类型
     * @return
     */
    public static Object rpc(ClassInfo classInfo , Class methodReturnType){
        String url = ((LocalServerManager) SpringUtils.getBean("localServerManager")).getHttpHostUrl(classInfo.getServiceName());
        if(StringUtils.isBlack(url) ) return null;
        Object result = OkHttpClientUtil.postClassInfo(url + functionUri, classInfo , methodReturnType);
        return result;
    }

    @PostMapping("/invoke")
    public Object consume(String jsonString) throws Exception {
        ClassInfo classInfo = JSON.parseObject(jsonString, ClassInfo.class);
        //使用反射调用 对应方法
        Object target = rpcMap.get(classInfo.getClassName());
        if(target == null){
                throw new RuntimeException("没有这个方法，非法调用");
        }
        List<Class> interfaceImpl = rpcMap.get(classInfo.getClassName());
        if(interfaceImpl == null || interfaceImpl.size() == 0){
            throw new RuntimeException("该方法在生产者并没有被实现，非法调用");
        }
        //TODO: 这里可以进一步优化实现类的调用，如果有多个实现类，那么到底要调用哪一个呢？
        //调用该实现类的对应方法
        Class impl = interfaceImpl.get(0);
        //下面是一般的调用方式
        Object instance = null;
        if(SpringUtils.isInSpring()){
            instance = SpringUtils.getBean(impl);
        }else{
             instance = impl.newInstance();
        }
        Method m =impl.getMethod(classInfo.getMethodName(), classInfo.getMethodParamtypes());
        Object result = m.invoke(instance, classInfo.getParams());
        return result;
    }

}
